/*
 * ccb_connector.c
 *
 *  Created on: 2014年11月30日
 *      Author: weiteng-jd
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <poll.h>
#include <errno.h>
#include <error.h>
#include <signal.h>
#include <unistd.h>
#include <fcntl.h>

#include "ccb_connector.h"

const short __STX__ = 0x55AA;
const uint32_t PKG_HEAD_LEN = sizeof(short) + sizeof(uint32_t);

typedef struct client_info
{
	int ifd;
	uint32_t dwExpectRecvLength; // 预期大小
	uint32_t dwRecvLength; // 当前接受大小
	uint32_t dwExpectSendLength; // 需要发送长度
	uint32_t dwSendLength; // 当前发送长度
	char szRecvBuffer[1024 * 1024 * 5];
	char szSendBuffer[1024 * 1024 * 5];
} client_info;

client_info *g_conn_clients[100];
uint32_t g_conn_clients_count = 0;

char g_conn_szBuffer[1024 * 1024 * 5];
int g_conn_iLength = 0;
int g_conn_istop = 0;
int g_conn_iserverfd = -1;

void (*g_conn_pfunRecv)(int, char *, uint32_t) = NULL;

void conn_new_client(int ifd)
{
	client_info * pclient_info = (client_info *) malloc(sizeof(client_info));
	pclient_info->ifd = ifd;
	pclient_info->dwExpectRecvLength = 0;
	pclient_info->dwRecvLength = 0;
	pclient_info->dwExpectSendLength = 0;
	pclient_info->dwSendLength = 0;

	g_conn_clients[g_conn_clients_count] = pclient_info;
	g_conn_clients_count++;
}

void conn_close_client(int index)
{
	printf("close fd:%d\n", g_conn_clients[index]->ifd);
	close(g_conn_clients[index]->ifd);
	free(g_conn_clients[index]);
	g_conn_clients_count--;
	g_conn_clients[index] = g_conn_clients[g_conn_clients_count];
	g_conn_clients[g_conn_clients_count] = NULL;
}

void conn_close_all_client()
{
	int i = 0;
	for (; i < g_conn_clients_count; i++)
	{
		printf("close: %d\n", g_conn_clients[i]->ifd);
		close(g_conn_clients[i]->ifd);
		free(g_conn_clients[i]);
	}
}

// 收到完整包
void conn_recv_pkg_data(int ifd, char *pszBuffer, uint32_t dwRecvLength)
{
	if (g_conn_pfunRecv != NULL)
	{
		g_conn_pfunRecv(ifd, pszBuffer, dwRecvLength);
	}
}

// 收到原始分包，需要解析组合
void conn_recv_raw_data(int index, char *pszBuffer, uint32_t dwRecvLength)
{
	if (index >= g_conn_clients_count || g_conn_clients[index] == NULL)
	{
		return;
	}

	if ((g_conn_clients[index]->dwRecvLength + dwRecvLength) > sizeof(g_conn_clients[index]->szRecvBuffer))
	{
		// 过大包丢弃。
		g_conn_clients[index]->dwRecvLength = 0;
		g_conn_clients[index]->dwExpectRecvLength = 0;
		memset(g_conn_clients[index]->szRecvBuffer, 0, sizeof(g_conn_clients[index]->szRecvBuffer));
		return;
	}

	memcpy(g_conn_clients[index]->szRecvBuffer + g_conn_clients[index]->dwRecvLength, pszBuffer, dwRecvLength);
	g_conn_clients[index]->dwRecvLength += dwRecvLength;

	// 多个包一起发过来
	while (g_conn_clients[index]->dwRecvLength > PKG_HEAD_LEN)
	{
		// 判断包头
		short sHeadTemp = 0;
		uint32_t dwHeadTempPos = 0;

		while (__STX__ != (*(short *) (g_conn_clients[index]->szRecvBuffer + dwHeadTempPos)))
		{
			// 一直往后找包头
			dwHeadTempPos++;
			g_conn_clients[index]->dwRecvLength--;

			//到最后包头大小，还找不到包头
			if (g_conn_clients[index]->dwRecvLength < PKG_HEAD_LEN)
			{
				break;
			}
		}

		//找到包头
		if (g_conn_clients[index]->dwRecvLength >= PKG_HEAD_LEN)
		{
			// 获取包大小
			g_conn_clients[index]->dwExpectRecvLength = *((uint32_t*) (g_conn_clients[index]->szRecvBuffer + dwHeadTempPos + sizeof(short)));

			if (g_conn_clients[index]->dwExpectRecvLength == (g_conn_clients[index]->dwRecvLength - PKG_HEAD_LEN))
			{
				// 刚好接一個完整个包
				// printf(" get only one. \n");
				conn_recv_pkg_data(g_conn_clients[index]->ifd, g_conn_clients[index]->szRecvBuffer + dwHeadTempPos + PKG_HEAD_LEN, g_conn_clients[index]->dwExpectRecvLength);

				g_conn_clients[index]->dwRecvLength = 0;
				g_conn_clients[index]->dwExpectRecvLength = 0;
				memset(g_conn_clients[index]->szRecvBuffer, 0, sizeof(g_conn_clients[index]->szRecvBuffer));
				break;
			}
			else if (g_conn_clients[index]->dwExpectRecvLength < (g_conn_clients[index]->dwRecvLength - PKG_HEAD_LEN))
			{
				// 收到了一個以上的包
				// printf("get one more. \n");
				conn_recv_pkg_data(g_conn_clients[index]->ifd, g_conn_clients[index]->szRecvBuffer + dwHeadTempPos + PKG_HEAD_LEN, g_conn_clients[index]->dwExpectRecvLength);

				g_conn_clients[index]->dwRecvLength -= PKG_HEAD_LEN;
				g_conn_clients[index]->dwRecvLength -= g_conn_clients[index]->dwExpectRecvLength;

				// 保留未解析部分
				memmove(g_conn_clients[index]->szRecvBuffer, g_conn_clients[index]->szRecvBuffer + dwHeadTempPos + PKG_HEAD_LEN + g_conn_clients[index]->dwExpectRecvLength, g_conn_clients[index]->dwRecvLength);
				continue;
			}
			else
			{
				// 还没收到完整的包
				// printf(" not get complete.\n");
				memmove(g_conn_clients[index]->szRecvBuffer, g_conn_clients[index]->szRecvBuffer + dwHeadTempPos, g_conn_clients[index]->dwRecvLength);
				break;
			}
		}
		else
		{
			// 找不到包头，丢弃脏数据，保留未检查包头的数据，下次再检查
			// printf(" not found head.\n");
			memmove(g_conn_clients[index]->szRecvBuffer, g_conn_clients[index]->szRecvBuffer + dwHeadTempPos, g_conn_clients[index]->dwRecvLength);
			break;
		}
	}
}

void conn_startsvc(uint16_t wPort)
{
	int iRetCode = 0;
	memset(g_conn_clients, 0, sizeof(void *));

	g_conn_iserverfd = socket(AF_INET, SOCK_STREAM, 0);
	if (g_conn_iserverfd == -1)
	{
		printf("socket err.\n");
		return;
	}

	struct sockaddr_in server_addr;

	server_addr.sin_family = AF_INET;
	server_addr.sin_port = htons(wPort);
	server_addr.sin_addr.s_addr = INADDR_ANY;
	memset(server_addr.sin_zero, '\0', sizeof(server_addr.sin_zero));

//	int fval = fcntl(g_conn_iserverfd, F_GETFL, 0);
//	int status = fcntl(g_conn_iserverfd, F_SETFL, fval | O_NONBLOCK);
//	const int on = 1;
//	setsockopt(g_conn_iserverfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
	iRetCode = bind(g_conn_iserverfd, (struct sockaddr *) &server_addr, sizeof(server_addr));

	if (iRetCode == -1)
	{
		printf("bind err.\n");
		return;
	}

	iRetCode = listen(g_conn_iserverfd, 10);
	if (iRetCode == -1)
	{
		printf("bind err.\n");
		return;
	}

	g_conn_istop = 0;
	fd_set fds_read;
	while (g_conn_istop == 0)
	{
		// server fd
		struct pollfd pollfds[g_conn_clients_count + 1];
		pollfds[0].fd = g_conn_iserverfd;
		pollfds[0].events = POLLIN | POLLERR;

		// client fd
		int i = 0;
		for (; i < g_conn_clients_count; i++)
		{
			pollfds[i + 1].fd = g_conn_clients[i]->ifd;

			if (g_conn_clients[i]->dwExpectSendLength > g_conn_clients[i]->dwSendLength)
			{
				pollfds[i + 1].events = POLLIN | POLLERR | POLLOUT;
			}
			else
			{
				pollfds[i + 1].events = POLLIN | POLLERR;
			}
		}

		iRetCode = poll(pollfds, g_conn_clients_count + 1, 10);

		if (iRetCode == -1 && errno != EINTR)
		{
			continue;
		}
		else if (iRetCode == -1)
		{
			printf("poll err:%s\n", strerror(errno));
			continue;
		}
		else if (iRetCode == 0)
		{
			// poll timeout
			continue;
		}
		else
		{
			int i = 0;
			for (; i < g_conn_clients_count; i++)
			{
				// recv
				if (pollfds[i + 1].revents & POLLIN)
				{
					g_conn_iLength = recv(g_conn_clients[i]->ifd, g_conn_szBuffer, sizeof(g_conn_szBuffer), MSG_NOSIGNAL);

					if (g_conn_iLength == 0)
					{
						// client close
						conn_close_client(i);
						i--;
					}
					if (g_conn_iLength == -1 && (errno == EAGAIN || errno == EINTR))
					{
						// OK
					}
					else if (g_conn_iLength == -1)
					{
						// err close
						printf("errno:%d, error:%s\n", errno, strerror(errno));
						conn_close_client(i);
						i--;
					}

					conn_recv_raw_data(i, g_conn_szBuffer, g_conn_iLength);
				}

				//send
				if (pollfds[i + 1].revents & POLLOUT)
				{
					if (g_conn_clients[i]->dwExpectSendLength > g_conn_clients[i]->dwSendLength)
					{
						g_conn_iLength = send(g_conn_clients[i]->ifd, g_conn_clients[i]->szSendBuffer + g_conn_clients[i]->dwSendLength, g_conn_clients[i]->dwExpectSendLength - g_conn_clients[i]->dwSendLength, 0);

						if (g_conn_iLength == -1)
						{
							if (errno != EINTR && errno != EAGAIN && errno != EWOULDBLOCK)
							{
								conn_close_client(i);
								// err close
								printf("errno:%d, error:%s\n", errno, strerror(errno));
								i--;
							}
						}

						g_conn_clients[i]->dwSendLength += g_conn_iLength;

						if (g_conn_clients[i]->dwExpectSendLength == g_conn_clients[i]->dwSendLength)
						{
							g_conn_clients[i]->dwExpectSendLength = 0;
							g_conn_clients[i]->dwSendLength = 0;
						}
					}
				}
			}

			//accept
			int inewclientfd = 0;
			if (pollfds[0].revents & POLLIN)
			{
				int inewclientfd = accept(g_conn_iserverfd, NULL, NULL);
				printf("new client, fd:%d\n", inewclientfd);
				if (inewclientfd > 0)
				{
					conn_new_client(inewclientfd);
				}
			}
		}
	}

	conn_close_all_client();
	close(g_conn_iserverfd);
}

// 重置发送数据
void conn_reset_and_senddata(int ifd, char *pszData, uint32_t dwDataLength)
{
	int i = 0;
	for (; i < g_conn_clients_count; i++)
	{
		if (g_conn_clients[i]->ifd != ifd)
		{
			continue;
		}

		memcpy(g_conn_clients[i]->szSendBuffer, &__STX__, sizeof(short));
		memcpy(g_conn_clients[i]->szSendBuffer + sizeof(short), &dwDataLength, sizeof(uint32_t));

		if (pszData != NULL && dwDataLength > 0)
		{
			memcpy(g_conn_clients[i]->szSendBuffer + sizeof(short) + sizeof(uint32_t), pszData, dwDataLength);
		}

		g_conn_clients[i]->dwSendLength = 0;
		g_conn_clients[i]->dwExpectSendLength = dwDataLength + sizeof(short) + sizeof(uint32_t);
	}
}

// 继续发送数据
void conn_senddata(int ifd, char *pszData, uint32_t dwDataLength)
{
	int i = 0;
	for (; i < g_conn_clients_count; i++)
	{
		if (g_conn_clients[i]->ifd != ifd)
		{
			continue;
		}

		memcpy(g_conn_clients[i]->szSendBuffer + g_conn_clients[i]->dwSendLength, &__STX__, sizeof(short));
		memcpy(g_conn_clients[i]->szSendBuffer + g_conn_clients[i]->dwSendLength + sizeof(short), &dwDataLength, sizeof(uint32_t));
		if (pszData != NULL && dwDataLength > 0)
		{
			memcpy(g_conn_clients[i]->szSendBuffer + g_conn_clients[i]->dwSendLength + sizeof(short) + sizeof(uint32_t), pszData, dwDataLength);
		}

		g_conn_clients[i]->dwExpectSendLength = g_conn_clients[i]->dwExpectSendLength + sizeof(short) + sizeof(uint32_t) + dwDataLength;
	}
}

void conn_stopsvc()
{
	g_conn_istop = 1;
}

void conn_request_hander_for_recv(void (*pfunRecv)(int, char *, uint32_t))
{
	g_conn_pfunRecv = pfunRecv;
}

